
package org.dyndns.cooland.updater.downloader;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.Proxy;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

import org.dyndns.cooland.updater.UpdaterGUI;

public class OUTDownloader {
	
	private List<DownloaderEventListener>	_listeners	= new ArrayList<DownloaderEventListener>();
	
	public synchronized void addEventListener(DownloaderEventListener listener) {

		_listeners.add(listener);
	}
	
	public synchronized void removeEventListener(
			DownloaderEventListener listener) {

		_listeners.remove(listener);
	}
	
	private synchronized void changeEvent(DownloaderEvent event) {

		Iterator<DownloaderEventListener> i = _listeners.iterator();
		while (i.hasNext()){
			((DownloaderEventListener) i.next()).handleEvent(event);
		}
	}
	
	public OUTDownloader () {

	}
	
	static public boolean checkConnection(String url) {

		boolean result = false;
		HttpURLConnection con = null;
		try{
			con = (HttpURLConnection) new URL(url).openConnection();
			con.setRequestMethod("HEAD");
			result = (con.getResponseCode() == HttpURLConnection.HTTP_OK);
		}
		catch (Exception e){
			e.printStackTrace();
		}
		finally{
			if (con != null){
				try{
					con.disconnect();
				}
				catch (Exception e){
					e.printStackTrace();
				}
			}
		}
		return result;
	}
	
	static public void unZip(String zip_file, String unzip_path) throws IOException {

		File zip = new File(zip_file);
		if (!zip.canRead()){
			throw new FileNotFoundException("File " + zip.getAbsolutePath()
					+ " not found");
		}
		ZipFile zf = new ZipFile(zip_file);
		Enumeration files = zf.entries();
		File f = null;
		FileOutputStream fos = null;
		while (files.hasMoreElements()){
			try{
			ZipEntry entry = (ZipEntry)files.nextElement();
			InputStream eis = zf.getInputStream(entry);
			byte[] buffer=new byte[1024];
			int bytesRead=0;
			f=new File(unzip_path+File.separator+entry.getName());
			if (entry.isDirectory()){
				f.mkdirs();
				continue;
			}
			else{
				f.getParentFile().mkdirs();
				f.createNewFile();
			}
			fos = new FileOutputStream(f);
			while ((bytesRead=eis.read(buffer))!=-1){
				fos.write(buffer,0,bytesRead);
			}
			}
			catch (IOException e){
				e.printStackTrace();
				continue;
			}
			finally{
				if (fos!=null){
					try{
						fos.close();
					}
					catch(IOException e){
						//ignore
					}
				}
			}
			
		}
	}
	
	// Скачать файл заданный url и положить по пути file_path
	// force - перезаписать существующий, иначе сравнить по размеру/дате и
	// скачать только если файл новый или измененный
	//
	static public boolean downloadFile(String url, String file_path, boolean force,
			Proxy proxy, int connect_timeout, int read_timeout)
			throws MalformedURLException, FileNotFoundException, IOException {

		boolean result = false;
		
		URL inet_url = new URL(url);
		URLConnection urlConn = inet_url.openConnection(proxy);
		int size = urlConn.getContentLength();
		//long mod_time = urlConn.getLastModified();
		urlConn.setConnectTimeout(connect_timeout);
		urlConn.setReadTimeout(read_timeout);
		try{
			urlConn.setDoInput(true);
			urlConn.setUseCaches(false);
		}
		catch (IllegalStateException e){
			// already connected
		}
		InputStream is = null;
		is = urlConn.getInputStream();
		
		byte[] buffer = new byte[8 * 1024];
		OutputStream output = new FileOutputStream(file_path);
		try{
			int bytesRead;
			while ((bytesRead = is.read(buffer)) != -1){
				output.write(buffer, 0, bytesRead);
			}
		}
		finally{
			output.close();
		}
		
		if (is != null){
			is.close();
		}
		if ((new File(file_path)).length() == size){
			// error while downloading (may be bad inet connection)
			result = true;
		}
		
		return result;
	}
	
	public String getMD5Hash (String data){
		return org.apache.commons.codec.digest.DigestUtils
		.md5Hex(data);
	}
	
	//TODO заменить
	public File getCatalog(String site_url) {

		if (site_url == null || site_url.isEmpty()){
			return null;
		}
		// check for end slash
		if (!site_url.endsWith("/")){
			site_url += "/";
		}
		String md5 = getMD5Hash(site_url);
		String path = UpdaterGUI.MAIN_DIRECTORY + File.separator + "download"
				+ File.separator + md5;
		String catalog_path = path + File.separator + "catalog.zip";
		File ddir = new File(path);
		
		try{
			
			if (!ddir.isDirectory()){
				if (!ddir.mkdir()){
					// error creating catalog for download
					throw new IOException("Cant create catalog "
							+ ddir.getAbsolutePath() + " for download");
				}
			}
			
			String catalog_url = site_url + "catalog.zip";
			URL url = new URL(catalog_url);
			URLConnection urlConn = url.openConnection();
			
			// TODO compare with already exists file by mod_time
			// long mod_time = urlConn.getLastModified();
			int size = urlConn.getContentLength();
			
			// TODO set timeouts
			try{
				urlConn.setDoInput(true);
				urlConn.setUseCaches(false);
			}
			catch (IllegalStateException e){
				// already connected
			}
			InputStream is = null;
			try{
				is = urlConn.getInputStream();
			}
			catch (FileNotFoundException e){
				// file not found
				e.printStackTrace();
				return null;
			}
			
			byte[] buffer = new byte[8 * 1024];
			OutputStream output = new FileOutputStream(catalog_path);
			try{
				int bytesRead;
				int totalRead = 0;
				while ((bytesRead = is.read(buffer)) != -1){
					output.write(buffer, 0, bytesRead);
					totalRead += bytesRead;
					DownloaderEvent event = new DownloaderEvent(new Integer(100
							* totalRead / size), DownloaderEvent.PERCENT_CHANGE);
					changeEvent(event);
				}
			}
			finally{
				output.close();
				
			}
			
			if (is != null){
				is.close();
			}
			
			if ((new File(catalog_path)).length() != size){
				// error while downloading (may be bad inet connection)
				throw new IOException("Downloaded file size mismatch."
						+ catalog_path);
			}
			
		}
		catch (MalformedURLException mue){
			mue.printStackTrace();
			return null;
		}
		catch (IOException ioe){
			ioe.printStackTrace();
			return null;
		}
		catch (Exception e){
			e.printStackTrace();
			return null;
		}
		
		// unzip catalog.xml
		try{
			File cat = new File(catalog_path);
			if (!cat.canRead()){
				throw new FileNotFoundException("File " + cat.getAbsolutePath()
						+ " not found");
			}
			ZipFile zf = new ZipFile(catalog_path);
			ZipEntry ze = zf.getEntry("catalog.xml");
			if (ze == null){
				throw new FileNotFoundException("No catalog.xml found in "
						+ catalog_path);
			}
			
			InputStream is = zf.getInputStream(ze);
			File catalog = new File(path + File.separator + "catalog.xml");
			OutputStream out = new FileOutputStream(catalog);
			int read = 0;
			byte[] bytes = new byte[1024];
			while ((read = is.read(bytes)) != -1){
				out.write(bytes, 0, read);
			}
			is.close();
			zf.close();
			out.flush();
			out.close();
			
			return catalog;
		}
		catch (Exception e){
			e.printStackTrace();
			return null;
		}
		
	}
}
